package org.oschina.api.software.dao;

import java.util.Iterator;
import java.util.List;
import org.oschina.Constants;
import org.oschina.api.BaseDAO;
import org.oschina.api.discuss.discuss.dao.DiscussDAO;
import org.oschina.api.index.model.IndexHandleBean;
import org.oschina.api.software.model.Software;
import org.oschina.api.software.vo.SoftwareVo;
import org.oschina.helper.index.IndexHelper;
import org.oschina.helper.index.IndexResultBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class SoftwareDAO extends BaseDAO {

	@Autowired
	private IndexHelper indexHelper;
	@Autowired
	private DiscussDAO discussDAO;
	
	private final String findVo="SELECT sw.id,sw.title,sw.icon,sw.name,sw.home_page,sw.doc_url,sw.download_url,sw.introduce,sw.favorite_count,sw.type,sw.recommend_time,sw.create_time," +
			"us.id as 'author.id',us.username as 'author.username' "+
			"FROM "+Constants.DB_SOFTWARE+" sw,"+Constants.DB_USER+" us WHERE sw.author_id=us.id";

	private final String findVoByType=findVo+" AND sw.type=? ORDER BY sw.create_time LIMIT ?,?";
	/**
	 * 根据类型返回
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<SoftwareVo> findVoByType(int type,int first,int max)
	{
		return getQueryHelper().query(findVoByType, new Object[]{type,first,max}, SoftwareVo.class);
	}
	
	/**
	 * 根据类型返回数量
	 * @param type
	 * @return
	 */
	public int getCountByType(int type)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"type=?"}, new Object[]{type}, SoftwareVo.class);
	}
	
	private final String findVoByTypeOrderRecommend=findVo+" AND sw.type=? AND sw.recommend_time!=0 ORDER BY sw.recommend_time DESC LIMIT ?,?";
	/**
	 * 根据类型返回_根据推荐时间排序
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<SoftwareVo> findVoByTypeOrderRecommend(int type,int first,int max)
	{
		if(first==0)
		{
			List<SoftwareVo> result=getQueryHelper().query_cache(findVoByTypeOrderRecommend, new Object[]{type,first,max}, SoftwareVo.class);
			Iterator<SoftwareVo> iterator=result.iterator();
			while(iterator.hasNext())
			{
				SoftwareVo softwareVo=iterator.next();
				if(!softwareVo.getType().equals(type))
					iterator.remove();
			}
			
			return result;
		}
		return getQueryHelper().query(findVoByTypeOrderRecommend, new Object[]{type,first,max}, SoftwareVo.class);
	}
	
	/**
	 * 根据类型返回数量_根据推荐时间
	 * @param type
	 * @return
	 */
	public int getCountByTypeOrderRecommend(int type)
	{
		return (int) getQueryHelper().queryDataSum_cache(new String[]{"type=?","recommend_time!=0"}, new Object[]{type}, SoftwareVo.class);
	}
	
	private final String findVoById=findVo+" AND sw.id=?";
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public SoftwareVo findVoById(int id)
	{
		SoftwareVo cache=findVoByCache(id);
		if(cache!=null)
		{
			cacheData(cache);
			return cache;
		}
		
		return (SoftwareVo) getQueryHelper().queryForObject(findVoById, new Object[]{id}, SoftwareVo.class);
	}
	private SoftwareVo findVoByCache(int id)
	{
		return (SoftwareVo) getCacheHelper().hget(getIdKey(id), SoftwareVo.class);
	}
	
	private final String findVoByName=findVo+" AND sw.name=?";
	/**
	 * 根据名称返回
	 * @param name
	 * @return
	 */
	public SoftwareVo findVoByName(String name)
	{
		return (SoftwareVo) getQueryHelper().queryForObject(findVoByName, new Object[]{name}, SoftwareVo.class);
	}
	
	/**
	 * 根据类型搜索
	 * @param keywords
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public IndexResultBean<SoftwareVo> searchVoByType(String keywords[],int type,int first,int max)
	{
		StringBuilder where=null;
		for(String keyword:keywords)
		{
			if(where==null)
				where=new StringBuilder();
			else
				where.append(" OR ");
			
			where.append("(title:'");
			where.append(keyword);
			where.append("' OR introduce:'");
			where.append(keyword);
			where.append("' OR name:'");
			where.append(keyword);
			where.append("')");
		}
		where.append(" AND type:");
		where.append(type);
		return indexHelper.query(Constants.INDEX_PATH_SOFTWARE, where.toString(), new String[]{"create_time"}, new String[]{"desc"}, first, max, SoftwareVo.class);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	public void updateFavoriteCount(int id,int count)
	{
		getCacheHelper().hincr(getIdKey(id), "favorite_count", count);
		batchUpdate_queue("UPDATE "+Constants.DB_SOFTWARE+" SET favorite_count=favorite_count+? WHERE id=?", new Object[]{count,id});
	}

	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	public int updateType(int id,int type)
	{
		updateIndexById(id,new String[]{"type"}, new Object[]{type});
		updateCache(id,new String[]{"type"},new Object[]{type});
		return (int) getQueryHelper().update(new String[]{"type=?"}, new String[]{"id=?"}, new Object[]{type,id}, SoftwareVo.class);
	}
	
	/**
	 * 设置推荐
	 * @param softwareVo
	 * @param time
	 * @return
	 */
	public int setRecommend(SoftwareVo softwareVo,long time)
	{
		updateCache(softwareVo.getId(),new String[]{"recommend_time"},new Object[]{time});
		return (int) getQueryHelper().update(new String[]{"recommend_time=?"}, new String[]{"id=?"}, new Object[]{time,softwareVo.getId()}, SoftwareVo.class);
	}
	
	/**
	 * 编辑
	 * @param software
	 * @return
	 */
	public int edit(Software software)
	{
		updateIndexById(software.getId(),
				new String[]{"name","introduce"},
				new Object[]{software.getName(),software.getIntroduce()});
		
		updateCache(software.getId(),
				new String[]{"name","home_page","doc_url","download_url","introduce"},
				new Object[]{software.getName(),software.getHome_page(),software.getDoc_url(),software.getDownload_url(),software.getIntroduce()});
		
		return (int) getQueryHelper().update(new String[]{"name=?","home_page=?","doc_url=?","download_url=?","introduce=?"}, 
				new String[]{"id=?"}, 
				new Object[]{software.getName(),software.getHome_page(),software.getDoc_url(),software.getDownload_url(),software.getIntroduce(),software.getId()}, SoftwareVo.class);
	}
	
	/**
	 * 更新
	 * @param software
	 * @return
	 */
	public int update(Software software)
	{
		updateIndexById(software.getId(),
				new String[]{"name","title","icon","introduce"},  
				new Object[]{software.getName(),software.getTitle(),software.getIcon(),software.getIntroduce()});
		
		updateCache(software.getId(),
				new String[]{"name","title","icon","home_page","doc_url","download_url","introduce"},
				new Object[]{software.getName(),software.getTitle(),software.getIcon(),software.getHome_page(),software.getDoc_url(),software.getDownload_url(),software.getIntroduce()});
		
		return (int) getQueryHelper().update(new String[]{"name=?","title=?","icon=?","home_page=?","doc_url=?","download_url=?","introduce=?"}, 
				new String[]{"id=?"}, 
				new Object[]{software.getName(),software.getTitle(),software.getIcon(),software.getHome_page(),software.getDoc_url(),software.getDownload_url(),software.getIntroduce(),software.getId()}, SoftwareVo.class);
	}
	
	/**
	 * 创建
	 * @param software
	 * @return
	 */
	public Software create(Software software)
	{
		createIndex(new String[]{"id","name","title","icon","introduce","type","create_time"},  
				new Object[]{software.getId(),software.getName(),software.getTitle(),software.getIcon(),software.getIntroduce(),software.getType(),software.getCreate_time()});
		
		getQueryHelper().insert(new String[]{"id","author_id","name","title","icon","home_page","doc_url","download_url","introduce","favorite_count","type","recommend_time","create_time"},
				new Object[]{software.getId(),software.getAuthor(),software.getName(),software.getTitle(),software.getIcon(),software.getHome_page(),software.getDoc_url(),software.getDownload_url(),
				software.getIntroduce(),software.getFavorite_count(),software.getType(),software.getRecommend_time(),software.getCreate_time()}, SoftwareVo.class);
		return software;
	}

	private void updateCache(int id,String fields[],Object values[])
	{
		updateCache(Constants.CACHE_SOFTWARE,id,fields,values,Constants.TIMEOUT_SOFTWARE);
	}
	
	private void cacheData(SoftwareVo softwareVo)
	{
		discussDAO.needCacheByTag(softwareVo.getName());
	}
	
	private String getIdKey(Object id)
	{
		return getKey(Constants.CACHE_SOFTWARE, id);
	}
	
	private void updateIndexById(int id,String fields[],Object values[])
	{
		indexHandle(new IndexHandleBean(Constants.INDEX_PATH_SOFTWARE,"id:"+id,fields, values));
	}
	
	private void createIndex(String fields[],Object values[])
	{
		indexHandle(new IndexHandleBean(Constants.INDEX_PATH_SOFTWARE,fields, values));
	}
	
	private void indexHandle(IndexHandleBean indexHandleBean)
	{
		getMessageQueueHelper().send(Constants.QUEUE_INDEX_HANDLE,indexHandleBean);
	}
}